package com.calvin.study.multithread.threadlocal;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.calvin.study.utils.ThreadUtil;

public class ThreadLocalDemo02 {

	/**
	 * 模拟业务方法
	 */
	public static void serviceMethod() {
		// 睡眠500毫秒， 模拟执行所需的时间（耗时）
		ThreadUtil.sleepMilliSeconds(500);
		// 记录从开始调用到当前这个点（ "point-1"） 的耗时
		SpeedLog.logPoint("point-1 service");
		// 调用DAO方法： 模拟dao业务方法
		daoMethod();
		// 调用RPC方法： 模拟RPC远程业务方法
		rpcMethod();
	}

	/**
	 * 模拟dao业务方法
	 */
	public static void daoMethod() {
		// 睡眠400毫秒， 模拟执行所需的时间
		ThreadUtil.sleepMilliSeconds(400);
		// 记录上一个点（"point-1"） 到这里（"point-2"） 的耗时
		SpeedLog.logPoint("point-2 dao");
	}

	/**
	 * 模拟RPC远程业务方法
	 */
	public static void rpcMethod() {
		// 睡眠400毫秒， 模拟执行所需的时间
		ThreadUtil.sleepMilliSeconds(600);
		// 记录上一个点（"point-2"） 这里（"point-3"） 的耗时
		SpeedLog.logPoint("point-3 rpc");
	}
	
	public static void main(String[] args) {
		new Thread(() -> {
			// 开始耗时记录， 保存当前时间
			SpeedLog.beginSpeedLog();
			// 调用模拟业务方法
			ThreadLocalDemo02.serviceMethod();
			// 打印耗时
			SpeedLog.printCost();
			// 结束耗时记录
			SpeedLog.endSpeedLog();
		}).start();

		ThreadUtil.sleepSeconds(5);// 等待10秒看结果
	}
}

class SpeedLog {
	/**
	 * 记录调用耗时的本地Map变量
	 */
	private static final ThreadLocal<Map<String, Long>> TIME_RECORD_LOCAL = ThreadLocal
			.withInitial(SpeedLog::initialStartTime);

	/**
	 * 记录调用耗时的本地Map变量的初始化方法
	 */
	public static Map<String, Long> initialStartTime() {
		Map<String, Long> map = new HashMap<>();
		map.put("start", System.currentTimeMillis());
		map.put("last", System.currentTimeMillis());
		return map;
	}

	/**
	 * 开始耗时记录
	 */
	public static final void beginSpeedLog() {
		System.out.println("开始耗时记录");
		TIME_RECORD_LOCAL.get();
	}

	/**
	 * 结束耗时记录
	 */
	public static final void endSpeedLog() {
		TIME_RECORD_LOCAL.remove();
		System.out.println("结束耗时记录");
	}

	/**
	 * 耗时埋点
	 */
	public static final void logPoint(String point) {
		// 获取上一次的时间
		Long last = TIME_RECORD_LOCAL.get().get("last");
		// 计算上一次埋点到当前埋点的耗时
		Long cost = System.currentTimeMillis() - last;
		// 保存上一次埋点到当前埋点的耗时第
		TIME_RECORD_LOCAL.get().put(point + " cost:", cost);
		// 保存当前时间， 供下一次埋点使用
		TIME_RECORD_LOCAL.get().put("last", System.currentTimeMillis());
	}

	/**
	 * print方法的耗时
	 */
	public static final void printCost() {

		Iterator<Map.Entry<String, Long>> it = TIME_RECORD_LOCAL.get().entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, Long> entry = it.next();
			System.out.println(entry.getKey() + " =>" + entry.getValue());
		}
	}
}

